/*
 * Copyright (c) 2019-2029, ZeusOS Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author            Notes
 * 2021-03-23     longmain       first version
 */

#ifndef __ZOS_RTC_H__
#define __ZOS_RTC_H__

#include "zos_def.h"


/**
* @brief 用户可用的RTC ID，目前仅支持4个，用户不得增减ID，否则会造成平台内存越界
* @param
*/
typedef enum
{
  ZOS_RTC_TIMER_ID_1 = 5,
  ZOS_RTC_TIMER_ID_2 = 6,
  ZOS_RTC_TIMER_ID_3 = 7,
  ZOS_RTC_TIMER_ID_4 = 8,
  //ZOS_RTC_TIMER_ID_END = ZOS_RTC_TIMER_AP_ID_END,
} ZOS_RTC_TIMER_ID;

/**
* @brief  nb time struct
*/
struct nb_time_t
{
  zos_uint32_t tm_sec;  /* Seconds (0-59) */
  zos_uint32_t tm_min;  /* Minutes (0-59) */
  zos_uint32_t tm_hour; /* Hours (0-23) */
  zos_uint32_t tm_mday; /* Day of the month (1-31) */
  zos_uint32_t tm_mon;  /* Month (0-11) */
  zos_uint32_t tm_year; /* Years */
  zos_uint32_t tm_wday; /* Day of the week (0-6),always ignore */
  zos_uint32_t tm_yday; /* Day of the year (0-365),always ignore */
};

//RTC回调函数指针
typedef void (*zos_rtc_timeout_cb_t)(void *para);

/**
  * @brief   获取NTP网络时间，并更新到本地，以同步本地的世界时间
  * 
  * @param   ser_name, ntp服务器地址,NULL表示默认选用ntp1.aliyun.com
  * @param   timeout, 单位秒，填0时，平台内部使用默认值20秒；因NB速率低，建议该值不得小于20秒
  * @param   wall_clock,  世界时间返回值
  * 
  * @note    目前QS-100模组支持两种世界时间的更新途径，一种是3GPP在attach时后台更新当前世界时间；\n
  *  另一种是通过zos_rtc_get_ntp_time获取当前网络世界时间。
  * 
  * @warning    使用该接口必须确保之前已经PDP激活成功过，否则返回ZOS_ERROR;若timeout超时，则会返回ZOS_ETIMEOUT错误
  * @attention   由于RTC精度不高，如果客户需要更精准的当前时间，可以每隔一段时间调用该接口，通过NTP服务器更新当前世界时间。
  * 
  * 
  * @return  ZOS_EOK:获取成功 , ZOS_ERROR:获取失败 , ZOS_ETIMEOUT:获取超时
  */
zos_err_t zos_rtc_get_ntp_time(const char *ser_name, int timeout, struct nb_time_t *wall_clock);

/**
  * @brief   根据时区获取NTP网络时间，并更新到本地，以同步本地的世界时间
  * @param   ser_name, ntp服务器地址,NULL表示默认选用ntp1.aliyun.com
  * @param   timeout, 单位秒，填0时，平台内部使用默认值20秒；因NB速率低，建议该值不得小于20秒
  *	@param   zone_sec ,time zone，必须设置当地的时区时间，例如在中国必须设置8*60*60
  * 
  * @warning 使用该接口必须确保之前已经PDP激活成功过，否则返回ZOS_ERROR；若timeout超时，则会返回ZOS_ETIMEOUT错误
  * @note    该接口与zos_rtc_get_ntp_time的差异仅在于时区的设置，如果不关心时区问题，不建议使用该接口
  * 
  * @return  ZOS_EOK:获取成功 , ZOS_ERROR:获取失败 , ZOS_ETIMEOUT:获取超时
  */
zos_err_t zos_rtc_set_by_NTP(const char *ser_name, int timeout, int zone_sec);

/**
  * @brief   获取本地的当前世界时间
  * @param   rtctime	   wall time,such as 2020/10/1 12:0:0
  *
  * @warning    使用该接口必须确保之前已经PDP激活成功过，即已经获取过最新的世界时间；否则返回ZOS_ERROR
  * @attention  该接口未考虑时区问题，获取的就是当地的年月日事件，例如北京时间。该接口不能用于带时区功能的转换
  * 
  * @return  ZOS_EOK:获取成功 , ZOS_ERROR:获取失败
  */
zos_err_t zos_rtc_get_time(struct nb_time_t *rtctime);

/**
  * @brief   获取某时区偏移的本地当前世界时间
  * @param   rtctime	   wall time,such as 2020/10/1 12:0:0
  * @param   offset_sec	   get offset wall time,such as after 8 hours,maybe negative value,such as -100S
  * 
  * @warning    使用该接口必须确保之前已经PDP激活成功过，即已经获取过最新的世界时间；否则返回ZOS_ERROR
  * @note    offset_sec时间偏移可以灵活使用，如设为0时，该接口则与zos_rtc_get_time功能一致，即获取当前的世界时间；\n
  *  再如offset_sec设为(0-8*60*60)，即向前8小时的世界时间，则对应当前北京时间的世界时间。
  * 
  * @return  ZOS_EOK:获取成功 , ZOS_ERROR:获取失败
  */
zos_err_t zos_rtc_get_UT_offset(struct nb_time_t *wall_clock, int offset_sec);

/**
  * @brief   获取RTC当前的秒数值，通常用于与某个时刻点进行比较，以决定是否超时
  * @param   need_UT_time  是否需要当前世界时间的秒数
  * @note    建议用户入参填0. \n
  * 
  *  如果用户想与世界时间绑定，则必须确保之前已经attach成功，否则会返回值0
  * @attention  用户使用该接口有两种场景，一种是网络通信相关的，此时入参需要填1，且需保证已经attach成功过； \n
  *   另一种是本地定时行为，不关心是否已联网，例如单核MCU工作场景。 \n
  *   用户在使用时，必须清楚使用该接口的目的，以填写正确的入参，否则会造成attach成功前后值的突变。
  * 
  *  @return  返回 秒数, 如果返回0表示当前未attach成功过
  */
zos_uint32_t zos_rtc_get_sec(int need_UT_time);

/**
  * @brief   用于系统从上电开始已经过了多少秒了，常用于用户的运行时间异常监控。
  *
  * @note    如果产品关心功耗，这个值总是小于5*60秒
  * 
  * @return  返回 秒数
  */
zos_uint32_t zos_rtc_get_working_time();

/**
  * @brief   用于查询上次正常深睡到现在过了多少秒，以供用户进行异常监控
  * 
  * @note    如果上次非正常深睡，返回值为0.
  * 
  * @return  返回 秒数。注意秒如果为0，则表示之前未进入深度睡眠
  */
zos_uint32_t zosc_rtc_get_last_work_offset();

/**
  * @brief   设置某ID超时RTC事件
  * @param   timer_id	   ID
  * @param   sec_offset	 下一个超时偏移量（秒）
  * @param   callback	   timeout callback
  * @param   data	       timeout callback  input param
  * 
  * @note    对于周期性的定时功能，必须设置随机的超时时刻点，以减轻对运营商基站的运营压力，建议使用zos_rtc_set_by_day或zos_rtc_set_by_week接口
  * 
  * @warning 如果超时周期<1小时，必须联系骑士科技FAE！！！
  * @attention  超时回调函数不得使用阻塞机制，且代码不能运行太长事件，以免影响其他RTC的运行时序
  * 
  * @return  ZOS_EOK:创建成功 , ZOS_ERROR:创建失败
  */
zos_err_t zos_rtc_timer_create(char timer_id, int sec_offset, zos_rtc_timeout_cb_t callback, void *data);

/**
  * @brief   设置每天某个时间段的随机RTC事件。例如15:00--18:00区间内,则zos_rtc_set_by_week(ZOS_RTC_TIMER_ID_1,user_rtc_timeout_cb,NULL,7,15,5*60*60,0,0)
  * @param   timer_id, ZOS_RTC_TIMER_ID类型
  * @param   hour_start, 开始时间(小时)
  * @param   sec_span,  随机时间范围(秒),该值始终大于0 . 用于RTC随机唤醒时间段范围以减少基站压力，提高通信成功率
  * @param   min, 
  * @param   sec,
  * 
  * @note    用于设置每天某时间段的周期性定时行为，为了减轻基站的通信压力，每个机器具体的时刻点具有随机性。
  * @warning    使用该接口必须确保之前已经PDP激活成功过，即已经获取过最新的世界时间；否则返回ZIS_ERROR
  * @attention  超时回调函数不得使用阻塞机制，且代码不能运行太长事件，以免影响其他RTC的运行时序
  * 
  * @return  ZOS_EOK:设置成功 , ZOS_ERROR:设置失败
  */
zos_err_t zos_rtc_set_by_day(char timer_id, zos_rtc_timeout_cb_t callback, void *data, int hour_start, int sec_span, int min, int sec);

/**
  * @brief   设置每周某个时间段的随机RTC事件。例如设置星期天15:00--20:00区间内的RTC，则调用zos_rtc_set_by_week(ZOS_RTC_TIMER_ID_1,user_rtc_timeout_cb,NULL,7,15,5*60*60,0,0)
  * @param   timer_id, ZOS_RTC_TIMER_ID类型
  * @param   day_week,  范围:1-7
  * @param   hour_start, 开始时间(小时)
  * @param   sec_span,  随机时间范围(秒),该值始终大于0 . 用于RTC随机唤醒时间段范围以减少基站压力，提高通信成功率
  * @param   min,
  * @param   sec,
  * 
  * @note    用于设置每周某时间段的周期性定时行为，为了减轻基站的通信压力，每个机器具体的时刻点具有随机性。
  * @warning    使用该接口必须确保之前已经PDP激活成功过，即已经获取过最新的世界时间；否则返回XY_ERR
  * @attention  超时回调函数不得使用阻塞机制，且代码不能运行太长事件，以免影响其他RTC的运行时序
  * 
  * @return  ZOS_EOK:设置成功 , ZOS_ERROR:设置失败
  */
zos_err_t zos_rtc_set_by_week(char timer_id, zos_rtc_timeout_cb_t callback, void *data, int day_week, int hour_start, int sec_span, int min, int sec);

/**
  * @brief   删除RTC定时器
  * @param   timer_id	   ZOS_RTC_TIMER_ID类型
  * 
  * @note    如果周期<1小时，必须联系骑士科技FAE！！！
  * 
  * @return  ZOS_EOK:删除成功 , ZOS_ERROR:删除失败
  */
zos_err_t zos_rtc_timer_delete(char timer_id);

/**
  * @brief   获取某用户定时器ID的下一次超时的秒数偏移。如果返回0，则表示当前ID未设置定时事件
  * @param   timer_id	   ZOS_RTC_TIMER_ID类型
  * 
  * @note    该接口常用于异常重启等保护使用，即重启后查看是否有效，若无效，则重设该定时器。 \n
  *          客户在设置RTC事件时，必须充分考虑各种异常造成的事件未设置成功问题。
  * 
  * @return  秒数:返回距离下次超时的秒数偏移 , 如果返回0，则表示当前ID未设置定时事件
  */
zos_uint32_t zos_rtc_next_offset_by_ID(char timer_id);

/**
  * @brief   利用1970年到现在的毫秒数,转换到出当前时间
  * @param   msec	   转换后的ms偏移量
  * @param   result	   struct nb_time_t * 类型的时间结构体
  * @note
  */
void zos_rtc_get_time_by_msec(const zos_uint64_t msec, struct nb_time_t *result);

/**
  * @brief  获取1970年到现在的毫秒数
  * @param   tp	   struct nb_time_t *类型的时间结构体
  * @note   返回值为毫秒
  */
zos_uint64_t zos_rtc_get_time_msec(struct nb_time_t *tp);


#endif
